﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using zTalk.Network;
using System.Configuration;

namespace zTalk
{
    public partial class Contacts : Window
    {
        public ObservableCollection<UserItem> UserItems { get; set; }
        private Dictionary<string, Chat> chatWindows;
        private Timer timerAfk;
        private bool autoAfk = false;
        private int intervalAfk;

        public Contacts()
        {
            InitializeComponent();

            this.Left = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width - 270;
            this.Top = 50;

            chatWindows = new Dictionary<string, Chat>();
            App.Handler.Message += new PacketEventHandler(Handler_Message);
            App.Handler.UserChange += new PacketEventHandler(Handler_UserChange);
            App.Handler.UserLogout += new PacketEventHandler(Handler_UserLogout);
            App.Handler.FileSend += new PacketEventHandler(Handler_FileSend);

            App.TrayIcon.DoubleClick += new EventHandler(TrayShow_Click);
            App.TrayIcon.ContextMenu.MenuItems[0].Click += new EventHandler(TrayShow_Click);
            App.TrayIcon.ContextMenu.MenuItems[2].Click += new EventHandler(TrayExit_Click);
            App.TrayIcon.Visible = true;
            App.TrayIcon.ShowBalloonTip(5000);

            ContextMenu cm = new ContextMenu();

            MenuItem miOnline = new MenuItem();
            miOnline.Header = "Online";
            miOnline.Click += new RoutedEventHandler(Status_Click);
            cm.Items.Add(miOnline);

            MenuItem miAfk = new MenuItem();
            miAfk.Header = "Away From Keyboard";
            miAfk.Click += new RoutedEventHandler(Status_Click);
            cm.Items.Add(miAfk);

            imgStatus.ContextMenu = cm;

            intervalAfk = int.Parse(ConfigurationManager.AppSettings["AutoAFK"]);
            timerAfk = new Timer();
            timerAfk.Interval = 2000;
            timerAfk.AutoReset = true;
            timerAfk.Elapsed += new ElapsedEventHandler(timerAfk_Elapsed);
            timerAfk.Start();
        }

        void timerAfk_Elapsed(object sender, ElapsedEventArgs e)
        {
            int time = App.GetLastInputTime();

            if (time > intervalAfk && App.User.Status != UserStatus.AFK)
            {
                App.User.Status = UserStatus.AFK;
                autoAfk = true;
                App.SendUserChange();
            }
            if (time < intervalAfk && App.User.Status == UserStatus.AFK && autoAfk == true)
            {
                App.User.Status = UserStatus.ONLINE;
                autoAfk = false;
                App.SendUserChange();
            }
        }

        void Handler_FileSend(object sender, PacketEventArgs ea)
        {
            FileProto proto = (FileProto)ea.Result;

            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate {
                FileTransfer ft = new FileTransfer();
                ft.SendMode = false;
                ft.User = new UserItem { Username = proto.Source };
                ft.FileInfo = proto;
                ft.Show();
                ft.Focus();
            }));

            // !!!!!!CACHE FILENAMES         
        }

        void TrayShow_Click(object sender, EventArgs e)
        {
            Show();
            Focus();
        }

        void TrayExit_Click(object sender, EventArgs e)
        {
            App.TrayIcon.Visible = false;
            App.Current.Shutdown();
        }

        void Handler_UserChange(object sender, PacketEventArgs ea)
        {
            UserItem changes = (UserItem)ea.Result;

            var item = (from i in UserItems
                        where i.Username == changes.Username
                        select i).Single();
            item.Status = changes.Status;
            item.About = changes.About;
            item.Avatar = changes.Avatar;

            if (chatWindows.ContainsKey(changes.Username))
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate {
                    chatWindows[changes.Username].User = item;
                    chatWindows[changes.Username].DataContext = item;
                }));
            }
        }

        void Handler_UserLogout(object sender, PacketEventArgs ea)
        {
            string username = (string)ea.Result;

            var item = (from i in UserItems
                        where i.Username == username
                        select i).Single();
            item.Status = UserStatus.OFFLINE;

            if (chatWindows.ContainsKey(username))
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate {
                    chatWindows[username].User = item;
                    chatWindows[username].DataContext = item;
                }));
            }
        }

        void Handler_Message(object sender, PacketEventArgs ea)
        {
            MessageProto message = (MessageProto)ea.Result;

            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate {
                if (chatWindows.ContainsKey(message.Source) == false)
                {
                    Chat chat = new Chat();
                    chat.User = new UserItem { Username = message.Source };
                    chat.GetUser();
                    chatWindows[message.Source] = chat;
                    chat.Show();
                }
                chatWindows[message.Source].Message(message.Source, message.Text, message.Time);
                chatWindows[message.Source].Show();
                chatWindows[message.Source].Focus();
            }));
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            DataContext = App.User;
            lbContacts.ItemsSource = UserItems;

            Packet p = Packet.Create(Opcodes.GET_MESSAGES, "");
            App.Client.SendPacket(p);
        }

        private void AddFriend_Click(object sender, RoutedEventArgs e)
        {
            AddFriend af = new AddFriend();
            af.ShowDialog();
        }

        private void lbContacts_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            object item = null;
            item = GetElementFromPoint(lbContacts, e.GetPosition(lbContacts));
            if (item != null)
            {
                UserItem user = (UserItem)item;
                if (chatWindows.ContainsKey(user.Username) == false)
                {
                    Chat chat = new Chat();
                    chat.User = (UserItem)item;
                    chatWindows[user.Username] = chat;
                    chat.Show();
                }
                else
                {
                    chatWindows[user.Username].Show();
                    chatWindows[user.Username].Focus();
                }
            }
        }

        private object GetElementFromPoint(ListBox box, Point point)
        {
            UIElement element = (UIElement)box.InputHitTest(point);

            while (true)
            {
                if (element == box)
                {
                    return null;
                }

                object item = box.ItemContainerGenerator.ItemFromContainer(element);

                bool itemFound = !(item.Equals(DependencyProperty.UnsetValue));

                if (itemFound)
                {
                    return item;
                }

                element = (UIElement)VisualTreeHelper.GetParent(element);
            }
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            e.Cancel = true;
            Hide();
        }

        private void EditProfile_Click(object sender, RoutedEventArgs e)
        {
            EditProfile ep = new EditProfile();
            ep.Show();
        }

        private void lbContacts_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Delete)
            {
                if (MessageBox.Show("Are you sure you want to remove your friend?", 
                    "Remove Friend", MessageBoxButton.YesNo, MessageBoxImage.Question) == 
                    MessageBoxResult.Yes)
                {
                    string username = ((UserItem)lbContacts.SelectedItem).Username;
                    
                    Packet p = Packet.Create(Opcodes.REMOVE_FRIEND,
                        Json.Encode<string[]>(new string[] { username }));
                    App.Client.SendPacket(p);

                    var x = UserItems.Where(u => u.Username == username).Single();
                    UserItems.Remove(x);
                }
            }
        }

        private void Status_Click(object sender, RoutedEventArgs e)
        {
            MenuItem mi = (MenuItem)e.Source;

            if (mi.Header.ToString() == "Online")
            {
                if (App.User.Status != UserStatus.ONLINE)
                {
                    App.User.Status = UserStatus.ONLINE;
                    App.SendUserChange();
                }
            }
            else
            {
                if (App.User.Status != UserStatus.AFK)
                {
                    App.User.Status = UserStatus.AFK;
                    App.SendUserChange();
                }
            }
        }
    }
}
